#ifndef PW_PBL_NAMEDVARIANT_HPP
#define PW_PBL_NAMEDVARIANT_HPP

#include "Variant.hpp"
#include "NamedType.hpp"
#include "Meta/Enum.hpp"

namespace pw_pbl
{
	template <ccNamedType... TNs>
	struct NamedVariant : public Variant<typename TNs::type...>
	{
	private:
		using _variant = Variant<typename TNs::type...>;

	public:
		using _variant::_variant;
		using _variant::emplace;
		using _variant::operator=;

		using Enum = Meta::Enum<TNs::name...>;
		template <Meta::Str Name>
		static constexpr size_t EIndex = Enum::template value<Name>;

		template <Meta::Str Name>
		constexpr decltype(auto) get() { return std::get<EIndex<Name>>(*this); }
		template <Meta::Str Name>
		constexpr decltype(auto) get() const { return std::get<EIndex<Name>>(*this); }

		template <Meta::Str Name>
		constexpr decltype(auto) get_if() { return std::get_if<EIndex<Name>>(*this); }
		template <Meta::Str Name>
		constexpr decltype(auto) get_if() const { return std::get_if<EIndex<Name>>(*this); }

		template <Meta::Str Name, typename... V>
		constexpr decltype(auto) emplace(V &&...v) { return _variant::template emplace<EIndex<Name>>(std::forward<V>(v)...); }
	};
} // namespace pw_pbl

template <pw_pbl::ccNamedType... T>
struct std::variant_size<pw_pbl::NamedVariant<T...>> : public std::integral_constant<std::size_t, sizeof...(T)>
{};

template <pw_pbl::ccNamedType... T>
struct std::variant_size<const pw_pbl::NamedVariant<T...>> : public std::integral_constant<std::size_t, sizeof...(T)>
{};

#endif // PW_PBL_NAMEDVARIANT_HPP
